//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#ifndef __KPRXSTUB_H__
#define __KPRXSTUB_H__

#define GET_LENGTH(a) ((a) & 0x3f)
#define GET_IN_INTERFACE_MARK(a) ((a) & 0x80)
#define GET_OUT_INTERFACE_MARK(a) ((a) & 0x40)
#define GET_INTERFACE_MARK(a) ((a) & 0xc0)
#define MAX_OUT_INTERFACE_ACCOUNT 32

class CObjectProxy;

#ifdef _EVC
#pragma     pack(1)
#endif

class __PACKED__ CInterfaceProxy
{
public:
    static CARAPI_(PInterface) S_Probe(
            /* [in] */ CInterfaceProxy *pThis,
            /* [in] */ REIID riid);

    static CARAPI_(UInt32) S_AddRef(
            /* [in] */ CInterfaceProxy *pThis);

    static CARAPI_(UInt32) S_Release(
            /* [in] */ CInterfaceProxy *pThis);

    CARAPI BufferSize(
            /* [in] */ UInt32 uMethodIndex,
            /* [in] */ UInt32 *puArgs,
            /* [out] */ UInt32 *puInSize,
            /* [out] */ UInt32 *puOutSize);

    CARAPI MarshalIn(
            /* [in] */ UInt32 uMethodIndex,
            /* [in] */ UInt32 *puArgs,
            /* [out] */ MarshalHeader *pHeader);

    CARAPI UnmarshalOut(
            /* [in] */ UInt32 uMethodIndex,
            /* [out] */ MarshalHeader *pHeader,
            /* [in] */ UInt32 *puArgs);

    CARAPI_(UInt32) CountMethodArgs(
            /* [in] */ UInt32 uMethodIndex)
    {
        return GET_LENGTH((m_pInfo->methods[uMethodIndex]).reserved1);
    }

    static CARAPI ProxyEntry(
            /* [in] */ UInt32 *puArgs);

public:
    PVoid               m_pvVptr;       // must be first member
    PVoid               m_pvProxyEntry; // must be m_pvVptr's next member

    oid_t                 m_oid;
    UInt32              m_uIndex;       // interface index in object
    PContext            m_pContext;
    CObjectProxy        *m_pOwner;
    const CIInterfaceEntry *m_pInfo;
};

#ifdef _EVC
#pragma     pack()
#endif

interface IProxy : public IInterface
{
    virtual CARAPI IndexQI(
            /* [in] */ UInt32 uIndex,
            /* [out] */ PInterface *ppObj) = 0;

    virtual CARAPI QI_Index(
             /* [in] */ IInterface **ppObj,    // yipeng: why IInterface** ?
             /* [out] */UInt32* pIndex ) = 0;

    virtual CARAPI GetOid(
            /* [out] */ oid_t *pOid) = 0;

    virtual CARAPI  GetClsid(
            /* [out] */ EMuid *pClsid) = 0;

    virtual CARAPI GetClassEntry(
            /* [out] */ UInt32 * pInfo) = 0;
};

class CObjectProxy : public IProxy
{
public:
    CARAPI_(PInterface) Probe(
            /* [in] */ REIID riid);

    CARAPI_(UInt32) AddRef(void);

    CARAPI_(UInt32) Release(void);

    CARAPI Aggregate(
            /* [in] */ AggregateType type,
            /* [in] */ PInterface pObj);

    CARAPI GetDomain(
            /* [out] */ PInterface *ppObj);

    CARAPI IndexQI(
            /* [in] */ UInt32 uIndex,
            /* [out] */ PInterface *ppObj);

    CARAPI QI_Index(
             /* [in] */ IInterface **ppObj,
             /* [out] */UInt32* pIndex );

    CARAPI GetOid(
            /* [out] */ oid_t *pOid);

    CARAPI GetClsid(
            /* [out] */ EMuid *pClsid);

    CARAPI GetClassEntry(
            /* [out] */ UInt32 * pInfo);

    CObjectProxy();
    virtual ~CObjectProxy();

    static CARAPI S_CreateObject(
            /* [in] */ oid_t oid,
            /* [in] */ REMuid rclsid,
            /* [in] */ UInt32 * pClsInfo,
            /* [in] */ PContext pContext,
            /* [out] */ IProxy **ppIProxy);

public:
    oid_t                 m_oid;
    UInt32              m_pInfo;
    int                 m_cInterfaces;
    CInterfaceProxy     *m_pInterfaces; // sizeis(m_cInterfaces)
    Interlocked         m_cRefs;
};

inline CObjectProxy::CObjectProxy()
{
    m_pInterfaces = NULL;
}

typedef struct InterfaceStruct
{
    struct
    {
        UInt32 m_vTable[1];
    } *m_vPtr;
}   InterfaceStruct;

class CInterfaceStub
{
public:
    CARAPI UnmarshalIn(
            /* [in] */ const CIMethodEntry *pMethodInfo,
            /* [in] */ MarshalHeader *pInHeader,
            /* [in] */  UInt32 * puOutInterfaceBuf,
            /* [in, out] */ UInt32 *puArgs);

    CARAPI MarshalOut(
            /* [in] */ const CIMethodEntry * pMethodInfo,
            /* [in] */ MarshalHeader * pInHeader,
            /* [in] */  UInt32 * puOutInterfaceBuf,
            /* [in, out] */ void * pvOutData,
            /* [in] */ bool_t bOnlyReleaseIn,
            /* [in] */ UInt32 * puKrnArgs);

public:
    union
    {
        IInterface             *m_pObject;
        InterfaceStruct     *m_pInterface;
    };

    const CIInterfaceEntry  *m_pInfo;
};

class CObjectStub : public IStub
{
public:
    CARAPI_(PInterface) Probe(
            /* [in] */ REIID riid);

    CARAPI_(UInt32) AddRef(void);

    CARAPI_(UInt32) Release(void);

    CARAPI Aggregate(
            /* [in] */ AggregateType type,
            /* [in] */ PInterface pObj);

    CARAPI GetDomain(
            /* [out] */ PInterface *ppObj);

    CARAPI Invoke(
            /* [in] */ void *pvInData,
            /* [in] */ UInt32 uInSize,
            /* [out] */ void *pvOutData,
            /* [in] */ UInt32 uOutSize);

    CARAPI GetOid(
            /* [out] */ oid_t *pOid);

    CARAPI GetClsid(
            /* [out] */ EMuid *pClsid);

    CARAPI InterfaceIndex(
            /* [in] */ PInterface pObj,
            /* [out] */ UInt32 *puIndex);

    CARAPI GetClassEntry(
            /* [out] */ UInt32 *pClassEntry);

    CObjectStub();
    virtual ~CObjectStub();

    static CARAPI S_CreateObject(
            /* [in] */ PInterface pObj,
            /* [out] */ IStub **ppIStub);

    static CARAPI S_CreateObject(
            /* [in] */ const wchar_t *pwszName,
            /* [in] */ PInterface pObj,
            /* [out] */ IStub **ppIStub);

public:
    oid_t                 m_oid;
    UInt32              m_pInfo;
    int                 m_cInterfaces;
    CInterfaceStub      *m_pInterfaces; // size_is(m_cInterfaces)
    Interlocked         m_cRefs;
};

inline CObjectStub::CObjectStub()
{
    m_pInterfaces = NULL;
    m_oid = 0;
}

extern ECode KernMarshalInterface(
        /* [in] */ PInterface pObj,
        /* [out] */ InterfacePack *pInterfacePack);

extern ECode KernUnmarshalInterface(
        /* [in] */ InterfacePack *pInterfacePack,
        /* [in] */ PContext pContext,
        /* [out] */ PInterface *ppObj);

#endif //__KPRXSTUB_H__
